package errors

//import (
//	"fmt"
//	"io"
//)
//
//// New returns an error with the supplied message.
//// New also records the stack trace at the point it was called.
//func New(message string) error {
//	return &fundamental{
//		msg:   message,
//		stack: callers(),
//	}
//}
//
//// Errorf formats according to a format specifier and returns the string
//// as a value that satisfies error.
//// Errorf also records the stack trace at the point it was called.
//func Errorf(format string, args ...interface{}) error {
//	return &fundamental{
//		msg:   fmt.Sprintf(format, args...),
//		stack: callers(),
//	}
//}
//
//// fundamental is an error that has a message and a stack, but no caller.
//type fundamental struct {
//	msg string
//	*stack
//}
//
//func (f *fundamental) Error() string { return f.msg }
//
//func (f *fundamental) Format(s fmt.State, verb rune) {
//	switch verb {
//	case 'v':
//		if s.Flag('+') {
//			io.WriteString(s, f.msg)
//			f.stack.Format(s, verb)
//			return
//		}
//		fallthrough
//	case 's':
//		io.WriteString(s, f.msg)
//	case 'q':
//		fmt.Fprintf(s, "%q", f.msg)
//	}
//}
//
//// WithStack annotates err with a stack trace at the point WithStack was called.
//// If err is nil, WithStack returns nil.
//func WithStack(err error) error {
//	if err == nil {
//		return nil
//	}
//
//	if e, ok := err.(*withCode); ok {
//		return &withCode{
//			err:   e.err,
//			code:  e.code,
//			cause: err,
//			stack: callers(),
//		}
//	}
//
//	return &withStack{
//		err,
//		callers(),
//	}
//}
//
//type withStack struct {
//	error
//	*stack
//}
//
//func (w *withStack) Cause() error { return w.error }
//
//// Unwrap provides compatibility for Go 1.13 error chains.
//func (w *withStack) Unwrap() error {
//	if e, ok := w.error.(interface{ Unwrap() error }); ok {
//		return e.Unwrap()
//	}
//
//	return w.error
//}
//
//func (w *withStack) Format(s fmt.State, verb rune) {
//	switch verb {
//	case 'v':
//		if s.Flag('+') {
//			fmt.Fprintf(s, "%+v", w.Cause())
//			w.stack.Format(s, verb)
//			return
//		}
//		fallthrough
//	case 's':
//		io.WriteString(s, w.Error())
//	case 'q':
//		fmt.Fprintf(s, "%q", w.Error())
//	}
//}
//
//// Wrap returns an error annotating err with a stack trace
//// at the point Wrap is called, and the supplied message.
//// If err is nil, Wrap returns nil.
//func Wrap(err error, message string) error {
//	if err == nil {
//		return nil
//	}
//	if e, ok := err.(*withCode); ok {
//		return &withCode{
//			err:   fmt.Errorf(message),
//			code:  e.code,
//			cause: err,
//			stack: callers(),
//		}
//	}
//
//	err = &withMessage{
//		cause: err,
//		msg:   message,
//	}
//	return &withStack{
//		err,
//		callers(),
//	}
//}
//
//// Wrapf returns an error annotating err with a stack trace
//// at the point Wrapf is called, and the format specifier.
//// If err is nil, Wrapf returns nil.
//func Wrapf(err error, format string, args ...interface{}) error {
//	if err == nil {
//		return nil
//	}
//
//	if e, ok := err.(*withCode); ok {
//		return &withCode{
//			err:   fmt.Errorf(format, args...),
//			code:  e.code,
//			cause: err,
//			stack: callers(),
//		}
//	}
//
//	err = &withMessage{
//		cause: err,
//		msg:   fmt.Sprintf(format, args...),
//	}
//	return &withStack{
//		err,
//		callers(),
//	}
//}
//
//// WithMessage annotates err with a new message.
//// If err is nil, WithMessage returns nil.
//func WithMessage(err error, message string) error {
//	if err == nil {
//		return nil
//	}
//	return &withMessage{
//		cause: err,
//		msg:   message,
//	}
//}
//
//// WithMessagef annotates err with the format specifier.
//// If err is nil, WithMessagef returns nil.
//func WithMessagef(err error, format string, args ...interface{}) error {
//	if err == nil {
//		return nil
//	}
//	return &withMessage{
//		cause: err,
//		msg:   fmt.Sprintf(format, args...),
//	}
//}
//
//type withMessage struct {
//	cause error
//	msg   string
//}
//
//func (w *withMessage) Error() string { return w.msg }
//func (w *withMessage) Cause() error  { return w.cause }
//
//// Unwrap provides compatibility for Go 1.13 error chains.
//func (w *withMessage) Unwrap() error { return w.cause }
//
//func (w *withMessage) Format(s fmt.State, verb rune) {
//	switch verb {
//	case 'v':
//		if s.Flag('+') {
//			fmt.Fprintf(s, "%+v\n", w.Cause())
//			io.WriteString(s, w.msg)
//			return
//		}
//		fallthrough
//	case 's', 'q':
//		io.WriteString(s, w.Error())
//	}
//}
//
//type withCode struct {
//	err   error
//	code  int
//	cause error
//	*stack
//}
//
//func WithCode(code int, format string, args ...interface{}) error {
//	return &withCode{
//		err:   fmt.Errorf(format, args...),
//		code:  code,
//		stack: callers(),
//	}
//}
//
//func WrapC(err error, code int, format string, args ...interface{}) error {
//	if err == nil {
//		return nil
//	}
//
//	return &withCode{
//		err:   fmt.Errorf(format, args...),
//		code:  code,
//		cause: err,
//		stack: callers(),
//	}
//}
//
//// Error return the externally-safe error message.
//func (w *withCode) Error() string { return fmt.Sprintf("%v", w) }
//
//// Cause return the cause of the withCode error.
//func (w *withCode) Cause() error { return w.cause }
//
//// Unwrap provides compatibility for Go 1.13 error chains.
//func (w *withCode) Unwrap() error { return w.cause }
//
//// Cause returns the underlying cause of the error, if possible.
//// An error value has a cause if it implements the following
//// interface:
////
////	type causer interface {
////	       Cause() error
////	}
////
//// If the error does not implement Cause, the original error will
//// be returned. If the error is nil, nil will be returned without further
//// investigation.
//func Cause(err error) error {
//	type causer interface {
//		Cause() error
//	}
//
//	for err != nil {
//		cause, ok := err.(causer)
//		if !ok {
//			break
//		}
//
//		if cause.Cause() == nil {
//			break
//		}
//
//		err = cause.Cause()
//	}
//	return err
//}
//
//func Is(err, target error) bool { return Is(err, target) }

import (
	pkgerrors "github.com/pkg/errors"
)

// ErrorCode defines the structure for application-specific error codes.
type ErrorCode struct {
	Code     int                    `json:"code"`
	HTTPCode int                    `json:"httpCode"`
	Message  string                 `json:"message"`
	Expose   bool                   `json:"-"`
	Severity string                 `json:"-"`
	Details  map[string]interface{} `json:"details,omitempty"`
}

// Error is a wrapper around both ErrorCode and pkg/errors.
type Error struct {
	*ErrorCode
	pkgErr error
}

// Error returns the error message and satisfies the error interface.
func (e *Error) Error() string {
	if e.pkgErr != nil {
		return e.pkgErr.Error()
	}
	return e.Message
}

// New creates a new Error with a message, wrapping it with pkg/errors for stack trace.
func New(code *ErrorCode, message string) *Error {
	return &Error{
		ErrorCode: code,
		pkgErr:    pkgerrors.New(message),
	}
}

// Wrap wraps an existing error with a message and an ErrorCode, preserving stack trace.
func Wrap(err error, code *ErrorCode, message string) *Error {
	return &Error{
		ErrorCode: code,
		pkgErr:    pkgerrors.Wrap(err, message),
	}
}

// Cause retrieves the original error.
func Cause(err error) error {
	var e *Error
	ok := pkgerrors.As(err, &e)
	if !ok {
		return err
	}
	return pkgerrors.Cause(e.pkgErr)
}

func (e *ErrorCode) WithDetail(key string, value interface{}) *ErrorCode {
	newErr := *e
	if newErr.Details == nil {
		newErr.Details = make(map[string]interface{})
	}
	newErr.Details[key] = value
	return &newErr
}

// WithDetails adds details to an ErrorCode and returns it.
func (e *ErrorCode) WithDetails(details map[string]interface{}) *ErrorCode {
	e.Details = details
	return e
}

// StackTrace returns the stack trace associated with the error.
func StackTrace(err error) pkgerrors.StackTrace {
	type stackTracer interface {
		StackTrace() pkgerrors.StackTrace
	}

	e, ok := err.(stackTracer)
	if !ok {
		return nil
	}
	return e.StackTrace()
}

// Is determines whether the error matches a target error.
func Is(err, target error) bool {
	if customErr, ok := err.(*Error); ok {
		return pkgerrors.Is(customErr.pkgErr, target)
	}
	return pkgerrors.Is(err, target)
}

// As finds the first error in err's chain that matches the target type.
func As(err error, target interface{}) bool {
	return pkgerrors.As(err, target)
}

// Unwrap returns the result of calling the Unwrap method on err, if err's type contains an Unwrap method returning error.
// Otherwise, Unwrap returns nil.
func Unwrap(err error) error {
	return pkgerrors.Cause(err) // 或使用 stderrors.Unwrap(err)，这取决于你如何封装和处理你的错误链。
}
